/*
 *  lib-smv: Matrix - Vector Library targeted to Structural Mechanics Problems
 *  Copyright (C) 2006-2008  St.Brcic, Lj.Zugic
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/** @file cArrays.h
 *  @brief Definition of cVector and cMatrix classes of complex numbers
 */

#ifndef _cARRAYS_H
#define _cARRAYS_H

#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <complex>
#include <cassert>
#include <string>
#include "iArrays.h"
#include "Arrays.h"

using namespace std;

namespace smv_lib
{
//! complex numbers with double real and imag parts
typedef complex<double> Complex;

//! small complex number - equal to zero
const Complex cTINY = Complex(1.0e-20, 1.0e-20);

//---------- forward declaration
class cMatrix;

/**
* \brief class cVector of complex numbers
*
*      cVector: Vector class of complex numbers
*
*/

class cVector
{
  private:
    //! good for Matrix-vector manipulation
    friend class cMatrix;
    //! array of Complex values
    //! number of vector elements
    Complex *data;           // array of cVector values
    int len;
    //! input stream
    ifstream in;             // input stream
    //! output stream
    ofstream out;            // output stream
    //! name of the Vector
    string Name;
    //! true if the Name is given
    bool isNameGiven;

  public:
    //! empty (default) constructor
    cVector();
    //! Vector with 'n' Complex elements of value 'd'
    cVector(int n, Complex d = Complex(0,0));
    //! Vector with given length 'n' and a name
    cVector(int n, string name);
    //! construct a Vector from a file
    cVector(const char* file);
    //! copy constructor
    cVector(const cVector& original);
    //! destructor
    ~cVector();

    //! assignment operator
    cVector& operator = (const cVector &original);
    //! set an element
    Complex& operator[](int i);
    //! get an element
    const Complex& operator[](int i) const;    
    //! cVector b = self + v
    cVector operator + (const cVector& v);
    //! cVector b = self - v
    cVector operator - (const cVector& v);
    //! is self == v ? (true if equal)
    bool operator == (const cVector& v);

    //-------------------- get and set functions
    //! get number of elements
    const int getLen() const { return len; }
    //! get element no 'i' (zero based)
    const Complex getData(int i) const;
    //! get the name
    const string& getName() const { return Name; }
    //! set length of a Vector
    void setSize(int n) { len = n; }
    //! set element no i with Complex data 'd'
    void setData(int i, Complex d);
    //! set the name
    void setName(string name);
    //------------------- member functions
    //! change size of a Vector
    void Resize(int n);
    //! make all zeroes
    void Zero(void);
    //! max element in a Vector (according to modulus)
    const Complex Max(void) const;
    //! min element in a Vector (according to modulus)
    const Complex Min(void) const;
    //! mean value of all elements
    const Complex Mean(void) const;
    //! dot product: Self * v
    Complex Dot(cVector& v);
    //! modulus of Self cVector (intensity)
    const Complex Modulus(void) const;
    //------------------- console output
    //! print all in one row
    void rPrint();
    //! print each element in a separete line
    void Print();
    //------------------- file I/O
    //! read from predefined file "Name.txt"
    cVector Read();
    //! write to predefined file  "Name.txt"
    void Write();
    //! read from a file
    cVector ReadFrom(const char* file);
    //! write to a file (L entries in a line)
    void WriteTo(const char* file, int L = 20);
    //------------------- stream I/O
    //! output stream
    friend ostream& operator << (ostream& s, const cVector& v);
};

//-------------- global cVector functions
//! dot product v1 * v2
Complex Dot(const cVector& v1, const cVector& v2);
//! product with double scalar: cVector b = x * v
cVector operator* (double x, const cVector& v);
//! product with double scalar: cVector b = x * v
cVector operator* (const cVector& v, double x);
//! modulus of a cVector v
Complex Modulus(const cVector& v);
//! output stream
std::ostream& operator << (ostream& s, const cVector& v);

//======================================================= end of cVector class

//======================================================= cMatrix class
//-------------------------------------------------------
/**
* \brief class cMatrix of complex numbers
*
*     cMatrix: Matrix class of complex numbers
*
*/

class cMatrix
{
  private:
    //! cMatrix data (cVector of rows m)
    cVector* m;
    //! number of rows and columns
    int rows,cols;
    //! input stream
    ifstream in;
    //! output stream
    ofstream out;
    //! name of the cMatrix
    string Name;
    //! true if the Name is given, false for default name cMATRIX
    bool isNameGiven;

  public:
    //! empty (default) constructor
    cMatrix();
    //! construct a cMatrix with given rows, columns and all elements
    cMatrix(int r, int c, Complex d = Complex(0,0));
    //! construct a Matrix with given rows, columns and a name
    cMatrix(int r, int c, string name);
    //! construct a cMatrix from a file
    cMatrix(const char* file);
    //! copy constructor
    cMatrix(const cMatrix& M);
    //! destructor
    ~cMatrix();
    //! assignment operator
    cMatrix& operator = (const cMatrix& M);

    //---------------------- get and set functions
    //! get number of rows
    int getRows() const { return rows; }                // number of rows
    //! get number of columns
    int getCols() const { return cols; }                // number of columns
    //! get element (i,j) - zero based
    const Complex getElement(int i, int j) const;      // Element (i,j) - zero based
    //! get elements in a row 'i' of a Matrix
    const cVector getRowData(int i) const;             // row of a cMatrix
    //! get elements in a column 'j' of a Matrix
    const cVector getColData(int j) const;             // column of a cMatrix
    //! set number of rows
    void setRows(int r) { rows = r; }
    //! set numer of columns
    void setCols(int c) { cols = c; }
    //! set the value 'val' to row 'i' and column 'j'
    void setElement(int i, int j, const Complex val);
    //! set all data in a row 'i' with Vector 'v'
    void setRowData(int i, const cVector& v);
    //! set all data in a column 'j' with Vector 'v'
    void setColData(int j, const cVector& v);
    //! set a name to the Matrix
    void setName(const string name);

    //------------------- arithmetic operations
    //! the sum of elements in a row
    Complex RowSum(int i);
    //! the sum of elements in a column
    Complex ColSum(int j);
    //! Matrix is assigned with all zero elements
    void Zero(void);
    //! Matrix becomes a unitary matrix
    void Identity(void);
    //! matrix becomes diagonal (all eleemnts are the same: 'd')
    void Diagonal(const Complex d);
    //! Matrix becomes diagonal (elements are equal to Vector 'v')
    void Diagonal(const cVector& v);

    //------------------- basic linear algebra
    //! cMatrix B = cMatrix self + cMatrix A
    cMatrix operator + (const cMatrix& A);
    //! cMatrix B = cMatrix self - cMatrix A
    cMatrix operator - (const cMatrix& A);
    //! cVector b = cMatrix self * cVector v
    cVector operator * (const cVector& v);
    //! cMatrix B = cMatrix self * s
    cMatrix operator * (const Complex s);
    //! cMatrix B = cMatrix self * cMatrix A
    cMatrix operator * (const cMatrix& A);
    //cMatrix& operator / (Complex s);        // cMatrix B = cMatrix self / s
    //cVector& operator / (cVector& v);       // cVector b = cMatrix self^(-1) * cVector v
    //cMatrix& operator / (cMatrix& A);       // cMatrix B = cMatrix self^(-1) * cMatrix A

    //cMatrix& calcLU (iVector& indx);              // performes LU decomposition of SELF
    //cVector& solveEQ(iVector& indx, cVector& b);  // solution of equations SELF * x = b
    //cMatrix& Inv();                                // inverse of cMatrix SELF
    //! transpose of cMatrix SELF
    cMatrix Tra();
    //cMatrix& operator ! ();
    //! transpose of cMatrix SELF
    cMatrix operator ~ ();
    //Complex  Det();
    //------------------- console output
    //! prints entries on a single line
    void Print();
    //! prints entries line by line
    void pPrint();
    //------------------- file I/O
    //! read from predefined file "cMATRIX.txt"
    cMatrix Read();
    //! write to predefined file  "cMATRIX.txt"
    void Write();
    //! read form a file
    cMatrix ReadFrom(const char* file);
    //! write to a file (L entries in a line)
    void WriteTo(const char* file, int L = 20);
    //------------------- stream I/O
    //! stream output
    friend ostream& operator << (ostream& s, const cMatrix& M);
};

//=============================== global cMatrix functions
//! Multiplication of cMatrix and a Complex scalar
cMatrix operator * (const Complex s, const cMatrix& M);
//! Multiplication of cMatrix and a Complex scalar
cMatrix operator * (const cMatrix& M, const Complex s);

//--- LU decomposition and Solution of equations
//void ludcmp(cMatrix& A, iVector& indx, Complex& d);    // LU decomposition of cMatrix A
//void lubksb(cMatrix& A, iVector& indx, cVector& b);   // Backsub stitution of LU decomposed cMatrix
//cVector& solveEQ(cMatrix& A, cVector& b);              // Solution of equations A * x = b  => x
//--- Inverse, Transpose, Determinant
//cMatrix& Inv(cMatrix& A);                              // inverse of cMatrix A
//! transpose of cMatrix A
cMatrix Tra(const cMatrix& A);
//Complex  Det(cMatrix& A);                              // determinant of cMatrix A
//--- stream I/O
//! stream output
std::ostream& operator << (ostream& s, const cMatrix& M);

}  // end of namespace smv_lib

#endif   // _cARRAYS_H

//================================ end of file
